#!/usr/bin/env python3
"""
字体解码器测试模块

测试字体反爬虫处理功能，确保代码质量符合openUBMC社区标准。
"""

import unittest
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock

import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))

from utils.font_decoder import (
    FontDecoder, OCRDecoder, FontReplacer, AdvancedFontDecoder,
    FontAntiCrawlHandler
)
from utils.font_constants import (
    UnicodeRanges, FontConstants, TextAnalysisConstants, ErrorCodes
)


class TestFontConstants(unittest.TestCase):
    """测试字体常量定义"""

    def test_unicode_ranges(self):
        """测试Unicode范围常量"""
        self.assertEqual(UnicodeRanges.CJK_UNIFIED_IDEOGRAPHS_START, 0x4E00)
        self.assertEqual(UnicodeRanges.CJK_UNIFIED_IDEOGRAPHS_END, 0x9FFF)
        self.assertEqual(UnicodeRanges.DIGITS_START, 0x0030)
        self.assertEqual(UnicodeRanges.DIGITS_END, 0x0039)

    def test_font_constants(self):
        """测试字体常量"""
        self.assertEqual(FontConstants.DEFAULT_CACHE_DIR, "font_cache")
        self.assertEqual(FontConstants.MAX_FONT_FILE_SIZE, 10 * 1024 * 1024)
        self.assertIn('.woff', FontConstants.FONT_EXTENSIONS)
        self.assertIn('.woff2', FontConstants.FONT_EXTENSIONS)

    def test_text_analysis_constants(self):
        """测试文本分析常量"""
        self.assertEqual(TextAnalysisConstants.UNKNOWN_CHAR_THRESHOLD, 0.3)
        self.assertGreater(TextAnalysisConstants.MAX_TEXT_LENGTH,
                          TextAnalysisConstants.MIN_TEXT_LENGTH)


class TestFontDecoder(unittest.TestCase):
    """测试字体解码器"""

    def setUp(self):
        """设置测试环境"""
        self.temp_dir = tempfile.mkdtemp()
        self.decoder = FontDecoder(self.temp_dir)

    def tearDown(self):
        """清理测试环境"""
        shutil.rmtree(self.temp_dir, ignore_errors=True)

    def test_extract_font_urls_font_face(self):
        """测试从@font-face规则提取字体URL"""
        html_content = """
        <style>
        @font-face {
            font-family: 'CustomFont';
            src: url('/assets/font/custom.woff2') format('woff2');
        }
        </style>
        """
        base_url = "https://example.com"
        font_urls = self.decoder.extract_font_urls(html_content, base_url)

        self.assertEqual(len(font_urls), 1)
        self.assertEqual(font_urls[0], "https://example.com/assets/font/custom.woff2")

    def test_extract_font_urls_link_tag(self):
        """测试从link标签提取字体URL"""
        html_content = '<link href="/fonts/custom.woff" rel="stylesheet">'
        base_url = "https://example.com"
        font_urls = self.decoder.extract_font_urls(html_content, base_url)

        self.assertEqual(len(font_urls), 1)
        self.assertEqual(font_urls[0], "https://example.com/fonts/custom.woff")

    def test_decode_text(self):
        """测试文字解码功能"""
        mapping_table = {
            'A': '杭',
            'B': '州',
            'C': '市'
        }
        garbled_text = "ABC"
        decoded_text = self.decoder.decode_text(garbled_text, mapping_table)

        self.assertEqual(decoded_text, "杭州市")

    def test_decode_text_empty_mapping(self):
        """测试空映射表的解码"""
        garbled_text = "ABC"
        decoded_text = self.decoder.decode_text(garbled_text, {})

        self.assertEqual(decoded_text, "ABC")

    @patch('requests.get')
    def test_download_font_file_success(self, mock_get):
        """测试成功下载字体文件"""
        # 模拟HTTP响应
        mock_response = Mock()
        mock_response.content = b'fake font data'
        mock_response.raise_for_status.return_value = None
        mock_get.return_value = mock_response

        font_url = "https://example.com/font.woff"
        result = self.decoder.download_font_file(font_url)

        self.assertIsNotNone(result)
        self.assertTrue(result.exists())
        self.assertEqual(result.name, "font.woff")

    @patch('requests.get')
    def test_download_font_file_large_size(self, mock_get):
        """测试下载过大的字体文件"""
        # 模拟大文件响应
        mock_response = Mock()
        mock_response.content = b'x' * (FontConstants.MAX_FONT_FILE_SIZE + 1)
        mock_response.raise_for_status.return_value = None
        mock_get.return_value = mock_response

        font_url = "https://example.com/large_font.woff"
        result = self.decoder.download_font_file(font_url)

        self.assertIsNone(result)

    def test_download_font_file_cached(self):
        """测试使用缓存的字体文件"""
        # 创建一个假的缓存文件
        cache_file = Path(self.temp_dir) / "cached_font.woff"
        cache_file.write_bytes(b'cached font data')

        font_url = "https://example.com/cached_font.woff"
        result = self.decoder.download_font_file(font_url)

        self.assertIsNotNone(result)
        self.assertEqual(result, cache_file)


class TestAdvancedFontDecoder(unittest.TestCase):
    """测试高级字体解码器"""

    def setUp(self):
        """设置测试环境"""
        self.decoder = AdvancedFontDecoder()

    def test_analyze_text_patterns_chinese(self):
        """测试中文文本模式分析"""
        text = "杭州市政府"
        patterns = self.decoder.analyze_text_patterns(text)

        self.assertEqual(patterns['chinese_chars'], 5)
        self.assertEqual(patterns['numbers'], 0)
        self.assertEqual(patterns['punctuation'], 0)
        self.assertEqual(patterns['unknown_chars'], 0)

    def test_analyze_text_patterns_mixed(self):
        """测试混合文本模式分析"""
        text = "杭州市2023年"
        patterns = self.decoder.analyze_text_patterns(text)

        self.assertEqual(patterns['chinese_chars'], 4)
        self.assertEqual(patterns['numbers'], 4)
        self.assertEqual(patterns['punctuation'], 0)
        self.assertEqual(patterns['unknown_chars'], 0)

    def test_analyze_text_patterns_with_punctuation(self):
        """测试带标点的文本模式分析"""
        text = "你好，世界！"
        patterns = self.decoder.analyze_text_patterns(text)

        self.assertEqual(patterns['chinese_chars'], 4)
        self.assertEqual(patterns['numbers'], 0)
        self.assertEqual(patterns['punctuation'], 2)
        self.assertEqual(patterns['unknown_chars'], 0)


class TestFontReplacer(unittest.TestCase):
    """测试字体替换器"""

    def setUp(self):
        """设置测试环境"""
        self.replacer = FontReplacer()

    def test_system_fonts_list(self):
        """测试系统字体列表"""
        self.assertIsInstance(self.replacer.system_fonts, list)
        self.assertIn('Arial', self.replacer.system_fonts)
        self.assertIn('Microsoft YaHei', self.replacer.system_fonts)

    @patch('selenium.webdriver.Chrome')
    def test_inject_font_replacement_script(self, mock_driver):
        """测试注入字体替换脚本"""
        mock_driver.execute_script = Mock()

        self.replacer.inject_font_replacement_script(mock_driver)

        # 验证脚本被执行
        mock_driver.execute_script.assert_called_once()

        # 检查脚本内容包含字体列表
        script_call = mock_driver.execute_script.call_args[0][0]
        self.assertIn('Arial', script_call)
        self.assertIn('Microsoft YaHei', script_call)


class TestOCRDecoder(unittest.TestCase):
    """测试OCR解码器"""

    def setUp(self):
        """设置测试环境"""
        self.decoder = OCRDecoder()

    def test_ocr_availability(self):
        """测试OCR可用性检查"""
        # OCR可用性取决于是否安装了easyocr
        self.assertIsInstance(self.decoder.ocr_available, bool)

    @patch('easyocr.Reader')
    def test_ocr_decoder_init_success(self, mock_reader_class):
        """测试OCR解码器成功初始化"""
        mock_reader = Mock()
        mock_reader_class.return_value = mock_reader

        decoder = OCRDecoder()

        self.assertTrue(decoder.ocr_available)
        self.assertEqual(decoder.reader, mock_reader)


class TestFontAntiCrawlHandler(unittest.TestCase):
    """测试字体反爬虫处理器"""

    def setUp(self):
        """设置测试环境"""
        self.temp_dir = tempfile.mkdtemp()
        self.handler = FontAntiCrawlHandler(self.temp_dir)

    def tearDown(self):
        """清理测试环境"""
        shutil.rmtree(self.temp_dir, ignore_errors=True)

    def test_handler_initialization(self):
        """测试处理器初始化"""
        self.assertIsInstance(self.handler.font_decoder, FontDecoder)
        self.assertIsInstance(self.handler.ocr_decoder, OCRDecoder)
        self.assertIsInstance(self.handler.font_replacer, FontReplacer)
        self.assertIsInstance(self.handler.advanced_decoder, AdvancedFontDecoder)

    def test_get_debug_info(self):
        """测试获取调试信息"""
        debug_info = self.handler.get_debug_info()

        self.assertIn('font_cache_dir', debug_info)
        self.assertIn('cached_fonts', debug_info)
        self.assertIn('ocr_available', debug_info)
        self.assertIn('font_mappings_count', debug_info)
        self.assertIn('constants_loaded', debug_info)
        self.assertIn('error_codes', debug_info)

        self.assertTrue(debug_info['constants_loaded'])
        self.assertIsInstance(debug_info['error_codes'], dict)

    @patch('selenium.webdriver.Chrome')
    def test_handle_font_obfuscation(self, mock_driver):
        """测试处理字体混淆"""
        html_content = """
        <style>
        @font-face {
            font-family: 'CustomFont';
            src: url('/assets/font/custom.woff2') format('woff2');
        }
        </style>
        """
        base_url = "https://example.com"

        with patch.object(self.handler.font_decoder, 'download_font_file') as mock_download:
            mock_download.return_value = None  # 模拟下载失败

            mapping_table = self.handler.handle_font_obfuscation(
                mock_driver, html_content, base_url
            )

            self.assertIsInstance(mapping_table, dict)


class TestErrorHandling(unittest.TestCase):
    """测试错误处理"""

    def test_error_codes_defined(self):
        """测试错误代码定义"""
        self.assertEqual(ErrorCodes.SUCCESS, 0)
        self.assertGreater(ErrorCodes.FONT_DOWNLOAD_FAILED, 1000)
        self.assertGreater(ErrorCodes.FONT_PARSE_FAILED, 1000)
        self.assertGreater(ErrorCodes.OCR_INIT_FAILED, 1000)


class TestIntegration(unittest.TestCase):
    """集成测试"""

    def setUp(self):
        """设置测试环境"""
        self.temp_dir = tempfile.mkdtemp()
        self.handler = FontAntiCrawlHandler(self.temp_dir)

    def tearDown(self):
        """清理测试环境"""
        shutil.rmtree(self.temp_dir, ignore_errors=True)

    def test_full_workflow_simulation(self):
        """测试完整工作流程模拟"""
        # 模拟HTML内容
        html_content = """
        <style>
        @font-face {
            font-family: 'TestFont';
            src: url('/test/font.woff') format('woff');
        }
        </style>
        <div style="font-family: TestFont;">测试文本</div>
        """

        # 提取字体URL
        font_urls = self.handler.font_decoder.extract_font_urls(
            html_content, "https://test.com"
        )

        self.assertEqual(len(font_urls), 1)
        self.assertEqual(font_urls[0], "https://test.com/test/font.woff")

        # 测试文本模式分析
        patterns = self.handler.advanced_decoder.analyze_text_patterns("测试文本123")
        self.assertEqual(patterns['chinese_chars'], 4)
        self.assertEqual(patterns['numbers'], 3)


if __name__ == '__main__':
    # 设置测试套件
    test_suite = unittest.TestSuite()

    # 添加测试用例
    test_classes = [
        TestFontConstants,
        TestFontDecoder,
        TestAdvancedFontDecoder,
        TestFontReplacer,
        TestOCRDecoder,
        TestFontAntiCrawlHandler,
        TestErrorHandling,
        TestIntegration
    ]

    for test_class in test_classes:
        tests = unittest.TestLoader().loadTestsFromTestCase(test_class)
        test_suite.addTests(tests)

    # 运行测试
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(test_suite)

    # 输出测试结果
    if result.wasSuccessful():
        print("\n✅ 所有测试通过！字体解码器功能正常。")
        exit(0)
    else:
        print(f"\n❌ 测试失败: {len(result.failures)} 个失败, {len(result.errors)} 个错误")
        exit(1)
